#include <algorithm>
#include "incognito.h"
#include "chord.h"
#include "dhashcli.h"
#include "dhblock.h"
#include "dhblock_chash.h"
#include "dhblock_noauth.h"
#include "dhblock_keyhash.h"
#include "incognito_proto.h"
#include "location.h"
#include "keymngr.h"
#include <modlogger.h>
#define warning modlogger ("incognito", modlogger::WARNING)
#define info  modlogger ("incognito", modlogger::INFO)
#define trace modlogger ("incognito", modlogger::TRACE)

// Pure virtual destructors still need definitions
incognito::~incognito () {}

ref<incognito>
incognito::produce_incognito (ptr<vnode> v, ref<dhash> dh)
{
	srand (time(NULL));
	return New refcounted<incognito_impl> (v,dh);
}

incognito_impl::~incognito_impl ()
{
}

incognito_impl::incognito_impl (ptr<vnode> node, ref<dhash> dh) : _host_node (node)
{
	info  << _host_node->my_ID () << "incognito_impl::incognito_impl() - info\n";
	warn  << _host_node->my_ID () << "incognito_impl::incognito_impl() - warn\n";
	warnx << _host_node->my_ID () << "incognito_impl::incognito_impl() - warnx\n";

	_dhcli = New refcounted<dhashcli> (node, dh);
	_keymngr = New refcounted<keymngr> ();
	_encmngr = New refcounted<encmngr> (mkref(this),_keymngr);
	_host_node->addHandler (incognito_program_1, wrap (this, &incognito_impl::dispatch));

	delaycb(15,0,wrap( mkref(this), &incognito_impl::onTick));

}
void incognito_impl::stop () {}
void incognito_impl::start () {}
void incognito_impl::print_stats () {
		warnx << "ID: " << _host_node->my_ID () << "\n";
			warnx << "Incognito Stats:\n";
}

void incognito_impl::onTick()
{
	delaycb(10,0,wrap( mkref(this), &incognito_impl::onTick));
}



// {{{ incognito_impl::dispatch()
void incognito_impl::dispatch (user_args *a)
{
	switch (a->procno)
	{
		case INCOGNITOPROC_NULL:
			warnx <<  "ID: " << _host_node->my_ID () << " incognito_impl::dispatch() - RPC CALLED!!!!!!\n";
			a->reply (NULL);
			break;
		case INCOGNITOPROC_STORE:
			on_store(a);
			break;
		case INCOGNITOPROC_ENC_STORE:
			on_enc_store(a);
			break;
		case INCOGNITOPROC_FETCH:
			on_fetch(a);
			break;
		case INCOGNITOPROC_DHKEY_EXCHANGE:
			on_dhkey_exchange(a);
			break;
		case INCOGNITOPROC_ENC_MESSAGE:
			on_enc_message(a);
			break;
		default:
			a->reject (PROC_UNAVAIL);
			break;
	}
}
// }}}

// {{{ Store
// {{{ Not encrypted
// {{{ void incognito_impl::on_store(user_args *a)
void incognito_impl::on_store(user_args *a)
{
	incognito_store_arg* sarg = a->Xtmpl getarg<incognito_store_arg> ();
	on_new_raw_store_req(*sarg);
	a->reply (NULL);
}
// }}}
// {{{ void incognito_impl::on_new_raw_store_req(const incognito_store_arg& req)
void incognito_impl::on_new_raw_store_req(const incognito_store_arg& req)
{
	warnx << "incognito_impl::on_new_raw_store_req(" << req.key_value << ");\n";
	
	if ( rand() > 0.25*RAND_MAX )
	{
		_host_node->find_successor(make_randomID(),
			wrap (mkref (this), &incognito_impl::on_new_raw_store_req_cb,
				New refcounted<incognito_store_arg> (req)));
	} else 
		publish(req);
}
// }}} 
// {{{ void incognito_impl::on_new_raw_store_req_cb( ptr<incognito_store_arg> req,  vec<chord_node> s, route search_path, chordstat status)
void incognito_impl::on_new_raw_store_req_cb(ptr<incognito_store_arg> req, vec<chord_node> s, route search_path, chordstat status)
{
	if (status != CHORD_OK) {
		warnx << "incognito_impl::on_new_raw_store_req_cb: find_successor failed: "
			<< status << " FIXME: " << __FILE__ << ":" << __LINE__ << "\n";
	} else {
		if (s.size()) {
			_encmngr->encrypt_and_send_store(s[0],req);
		} else {
			warnx << "incognito_impl::on_new_raw_store_req_cb: s.size()==0: "
				<< status << " FIXME: " << __FILE__ << ":" << __LINE__ << "\n";
		}
	}
}
// }}}  
// {{{  void incognito_impl::publish(const incognito_store_arg& req)
void incognito_impl::publish(const incognito_store_arg& req)
{
	warnx << "incognito_impl::publish(" << req.key_value << ");\n";
	warnx << "Publishing....\n";
	//warnx << "req.data >>" << req.data << "<<"
	warnx << " key_type: >>" << req.key_type << "<< key_value: >>" << req.key_value <<"<<\n";

	char tab[]={
		'0','1','2','3',
		'4','5','6','7',
		'8','9','A','B',
		'C','D','E','F'};
	const char *p=req.data.base();
	warnx << "incognito_impl::publish() - req.data[" << req.data.size() << "]: ";
	for (unsigned int i=0;i<std::min(req.data.size(),(size_t)64);++i) {
		char c[3]={tab[((unsigned char)p[i])>>4],tab[((unsigned char)p[i])&0x0f],0};
		warnx << c;
	}
	warnx << "\n";
/*----------------In case of NOAUTH block---------------------------------------------*/
	str data = str (req.data.base (), req.data.size ());
	str marshalled_data;
	if (req.key_type == DHASH_NOAUTH)
		marshalled_data = dhblock_noauth::marshal_block (data);
	else if (req.key_type == DHASH_CONTENTHASH)
		marshalled_data = dhblock_chash::marshal_block (data);
	else {
		warnx << "incognito_impl::publish: unknown key_type: "
			<< " FIXME: " << __FILE__ << ":" << __LINE__ << "\n";
		return;
	}
	
	warnx << " key_type: >>" << req.key_type << "\n";
	ref<dhash_block> block = New refcounted<dhash_block> (marshalled_data, req.key_type);
/*------------------------------------------------------------------------------------*/

//	ref<dhash_block> block =
//		New refcounted<dhash_block> (req.data.base() , req.data.size(), req.key_type);
	block->ID = req.key_value;

	//ptr<chordID> guess = NULL;

	_dhcli->insert (block,
			wrap (mkref (this), &incognito_impl::publish_insert_cb));
}
// }}}  
// {{{ v oid incognito_imp l::publish_insert_cb (dhash_stat status, vec<chordID> path)
void incognito_impl::publish_insert_cb (dhash_stat status, vec<chordID> path)
{
	if (status != DHASH_OK) {
		warnx << "incognito_impl::publish_insert_cb: insert failed: "
			<< status << " FIXME: " << __FILE__ << ":" << __LINE__ << "\n";
	} else {
		warnx << "incognito_impl::publish_insert_cb: OK\n";
	}
}
// }}} 
// }}} Not encrypted 
// {{{ Encrypted
// {{{ void incognito_impl::store_encrypted_data(chord_node &n,unsigned int seq,char *buf,size_t buf_size)
void incognito_impl::store_encrypted_data(chord_node &n,unsigned int seq,char *buf,size_t buf_size)
{
	warnx << "incognito_impl::store_encrypted_data()\n";

	ptr<incognito_enc_store_arg> arg = New refcounted<incognito_enc_store_arg> ();
	arg->caller_ID = _host_node->my_ID();
	arg->seq_num=seq;
	arg->enc_data.setsize(buf_size);
	memcpy (arg->enc_data.base (), buf, buf_size);

	warnx << "incognito_impl::store_encrypted_data() - arg->caller_ID=" << arg->caller_ID << "\n";
	warnx << "incognito_impl::store_encrypted_data() - arg->seq_num=" << arg->seq_num << "\n";
	char *buf2=arg->enc_data.base();
	char tab[]={
		'0','1','2','3',
		'4','5','6','7',
		'8','9','A','B',
		'C','D','E','F'};

	warn << "incognito_impl::store_encrypted_data() - arg->enc_data: ";
	for (unsigned int i=0;i<std::min(arg->enc_data.size(),(size_t)64);++i) {
		char p[3]={tab[((unsigned char)buf2[i])>>4],tab[((unsigned char)buf2[i])&0x0f],0};
		warnx << p;
	}   
	warnx << "\n";
	doRPC (n, incognito_program_1,
		INCOGNITOPROC_ENC_STORE, arg, NULL, wrap (mkref(this),&incognito_impl::store_encrypted_data_cb));
}
// }}} 
// {{{ void incognito_impl::store_encrypted_data_cb(clnt_stat err)
void incognito_impl::store_encrypted_data_cb(clnt_stat err)
{
	warnx << "incognito_impl::store_encrypted_data_cb() - clnt_stat=" << err << "\n";
	if (err) {
		warnx << "incognito_impl::store_encrypted_data_cb() - error="
			<< err << " FIXME: " << __FILE__ << ":" << __LINE__ << "\n";
		return;						// FIXME
	}
}
 // }}} 
// {{{  void incognito_impl::on_enc_store(user_args *a)
void incognito_impl::on_enc_store(user_args *a)
{
	warnx << "incognito_impl::on_enc_store()\n";
	
	ptr<incognito_enc_store_arg> arg = New refcounted<incognito_enc_store_arg> (*(a->Xtmpl getarg<incognito_enc_store_arg> ()));

	warnx << "incognito_impl::on_enc_store() - arg->caller_ID=" << arg->caller_ID << "\n";
	warnx << "incognito_impl::on_enc_store() - arg->seq_num=" << arg->seq_num << "\n";
	char *buf=arg->enc_data.base();
	char tab[]={
		'0','1','2','3',
		'4','5','6','7',
		'8','9','A','B',
		'C','D','E','F'};

	warn << "incognito_impl::on_enc_store() - arg->enc_data: ";
	for (unsigned int i=0;i<std::min(arg->enc_data.size(),(size_t)64);++i) {
		char p[3]={tab[((unsigned char)buf[i])>>4],tab[((unsigned char)buf[i])&0x0f],0};
		warnx << p;
	}   
	warnx << "\n";

	 _encmngr->decrypt(arg, wrap(mkref(this),&incognito_impl::on_enc_store_decrypt_cb,a));

	
}
// }}}
void incognito_impl::on_enc_store_decrypt_cb(user_args *a,incognito_store_arg req, decryptres res)
{
	warnx << "incognito_impl::on_enc_store_decrypt_cb() - res=" << res << "\n";
	on_new_raw_store_req(req);
	a->reply (NULL); // FIXME - check res and return status
}
// }}}  E ncrypted
// }}} Store

// {{{ Fetch
void incognito_impl::on_fetch(user_args *a)
{
	incognito_fetch_arg* arg = a->Xtmpl getarg<incognito_fetch_arg> ();
	warnx <<  "incognito_impl::on_fetch() - arg->key_type=" << arg->key_type << "\n";
	warnx <<  "incognito_impl::on_fetch() - arg->key_value=" << arg->key_value << "\n";

	ptr<incognito_raw_request> raw_msg=New refcounted<incognito_raw_request>;
	raw_msg->request_type=2;
	raw_msg->key_type=arg->key_type;
	raw_msg->key_value=arg->key_value;

	return on_new_raw_message(raw_msg, wrap (mkref (this), &incognito_impl::on_fetch_cb,a));
/* Do usunięcia


//	blockID (chordID k, dhash_ctype c);
//	void retrieve (blockID blockID, cb_ret cb,
//		int options = 0,
//		ptr<chordID> guess = NULL);
//	typedef callback<void, dhash_stat, ptr<dhash_block>, vec<ptr<location> > >::ptr cb_ret;

	_dhcli->retrieve (blockID(arg->key_value,arg->key_type),
			wrap (mkref (this), &incognito_impl::on_fetch_retrieve_cb,a));
//	_dhcli->retrieve (arg->key_value,arg->key_type,
//			wrap (mkref (this), &incognito_impl::on_fetch_retrieve_cb,a));
*/
}
void incognito_impl::on_fetch_cb(user_args *a, ptr<incognito_raw_request> raw_msg)
{
	warnx << "incognito_impl::on_fetch_cb() request_type=" << raw_msg->request_type << "\n";
	warnx << "incognito_impl::on_fetch_cb() status=" << raw_msg->status << " (" << DHASH_OK << "=OK)\n";
	if (raw_msg->status != DHASH_OK)
	{
		warnx << "incognito_impl::on_fetch_cb: statud != DHASH_OK"
			<< " FIXME: " << __FILE__ << ":" << __LINE__ << "\n";
		return;
	}
	ptr<incognito_fetch_res> res=New refcounted<incognito_fetch_res>;
	res->data.setsize(raw_msg->data.size());
	memcpy (res->data.base (), raw_msg->data.base(), raw_msg->data.size());

	a->reply(res);

}
/* Do usunięcia
void incognito_impl::on_fetch_retrieve_cb(user_args *a, dhash_stat status, ptr<dhash_block> block, route path)
{
	warnx << "incognito_impl::on_fetch_retrieve_cb() status=" << status << "\n";
	if (status != DHASH_OK)
	{
		warnx << "incognito_impl::on_fetch_retrieve_cb: stat != DHASH_OK"
			<< " FIXME: " << __FILE__ << ":" << __LINE__ << "\n";
		return;
	}
	vec<str> contents = get_block_contents (block->data, block->ctype);

	str buf;
	if (contents.size () == 1)
		buf = contents[0];
	else {
		assert (contents.size () > 0); 
		buf = contents[contents.size()-1];
	}   

	ptr<incognito_fetch_res> res=New refcounted<incognito_fetch_res>;
	res->data.setsize(buf.len());
	memcpy (res->data.base (), buf.cstr(), buf.len());

	a->reply(res);
}
*/
// }}} 

// {{{ Encrypted messages
void incognito_impl::on_enc_message(user_args *a)
{
	ptr<incognito_encrypted_request> enc_msg = New refcounted<incognito_encrypted_request> (*(a->Xtmpl getarg<incognito_encrypted_request> ()));
	warnx << "incognito_impl::on_enc_message() - caller_id=" << enc_msg->caller_ID << "\tseq=" << enc_msg->seq_num << "\n";
	return _encmngr->decrypt(enc_msg, wrap(mkref(this),&incognito_impl::on_enc_message_decrypt_cb,a));
}
void incognito_impl::on_enc_message_decrypt_cb(user_args *a, ptr<incognito_raw_request> raw_msg, encmngr::decrypt_res res)
{
	warnx << "incognito_impl::on_enc_message_decrypt_cb() - res=" << res << "\traw_msg->request_type=" << raw_msg->request_type << "\n";

	if (res != encmngr::INCOGNITO_EM_DECRYPT_OK) {
		warnx << "incognito_impl::on_enc_message_decrypt_cb(): Decryption failed! Preparing error response";
		ptr<incognito_raw_request> err_msg=New refcounted<incognito_raw_request>;
		err_msg->request_type=4; // Generic error
		err_msg->status=res;
		return on_enc_message_onrm_cb(a,err_msg);

		//REMOVE: incognito_encrypted_request* enc_msg = a->Xtmpl getarg<incognito_encrypted_request> ();

		//REMOVE: return _encmngr->encrypt(enc_msg->caller_ID,err_msg,wrap(mkref(this),&incognito_impl::on_enc_message_decrypt_error_cb,a));
	}
	// TODO: Check if request_type is correct

	return on_new_raw_message(raw_msg, wrap (mkref (this), &incognito_impl::on_enc_message_onrm_cb,a));
}
void incognito_impl::on_enc_message_onrm_cb(user_args *a, ptr<incognito_raw_request> raw_msg)
{
	warnx << "incognito_impl::on_enc_message_onrm_cb(user_args *a,ptr<incognito_raw_request> raw_msg)\n";
	incognito_encrypted_request* enc_msg = a->Xtmpl getarg<incognito_encrypted_request> ();

	return _encmngr->encrypt(enc_msg->caller_ID,raw_msg,wrap(mkref(this),&incognito_impl::on_enc_message_res_encrypt_cb,a));
}
void incognito_impl::on_enc_message_res_encrypt_cb(user_args *a, ptr<incognito_encrypted_request> enc_msg, encmngr::encrypt_res res)
{
	warnx << "incognito_impl::on_enc_message_res_encrypt_cb - res=" << res << "\n";
	if (res != encmngr::INCOGNITO_EM_ENCRYPT_OK) {
		warnx << "incognito_impl::on_enc_message_res_encrypt_cb (" << __FILE__ << ":"
			<< __LINE__ << "): FIXME FIXME FIXME - encryption of reply message failed. Don't know what to do...";
		// return;	// FIXME
	}

	return a->reply(enc_msg);
}
/* Usunąć
void incognito_impl::send_reply(user_args *a,ptr<incognito_raw_request> raw_msg)
{
	warnx << "incognito_impl::send_reply(user_args *a,ptr<incognito_raw_request> raw_msg)\n";
	incognito_encrypted_request* enc_msg = a->Xtmpl getarg<incognito_encrypted_request> ();

	return _encmngr->encrypt(enc_msg->caller_ID,raw_msg,wrap(mkref(this),&incognito_impl::send_reply_encrypt_cb,a));


}

void incognito_impl::send_reply_encrypt_cb(user_args *a, ptr<incognito_encrypted_request> enc_msg, encmngr::encrypt_res res)
{
	warnx << "incognito_impl::send_reply_encrypt_cb - res=" << res << "\n";
	if (res != encmngr::INCOGNITO_EM_ENCRYPT_OK) {
		warnx << "incognito_impl::send_reply_encrypt_cb (" << __FILE__ << ":"
			<< __LINE__ << "): FIXME FIXME FIXME - encryption of reply message failed. Don't know what to do...";
		// return;	// FIXME
	}

	return a->reply(enc_msg);
}
*/
/*
REMOVE: void incognito_impl::on_enc_message_decrypt_error_cb(user_args *a, ptr<incognito_encrypted_request> enc_msg, encmngr::encrypt_res res)
{
	warnx << "incognito_impl::on_enc_message_decrypt_error_cb - res=" << res << "\n";
	if (res != encmngr::INCOGNITO_EM_ENCRYPT_OK) {
		warnx << "incognito_impl::on_enc_message_decrypt_error_cb (" << __FILE__ << ":"
			<< __LINE__ << "): FIXME FIXME FIXME - encryption of error message failed. Don't know what to do...";
		// return;	// FIXME
	}

	return a->reply(enc_msg);
}
*/

void incognito_impl::on_new_raw_message(ptr<incognito_raw_request> raw_msg, incognito_impl::cb_onrm cb)
{
	int delay=(int)(50000.0*rand()/RAND_MAX);									// 0 to 50 ms
	delaycb(0, delay, wrap (mkref (this), &incognito_impl::on_new_raw_message_delay_cb, raw_msg, cb));	// seconds, nanoseconds, callback
}
void incognito_impl::on_new_raw_message_delay_cb(ptr<incognito_raw_request> raw_msg, incognito_impl::cb_onrm cb)
{
	warnx << "incognito_impl::on_new_raw_message() - raw_msg->request_type=" << raw_msg->request_type << ";\n";
	
	if ( rand() > 0.25*RAND_MAX )
	{
		_host_node->find_successor(make_randomID(),
			wrap (mkref (this), &incognito_impl::on_new_raw_message_find_successor_cb, cb, raw_msg));
	} else {
		switch(raw_msg->request_type) {
			case 0: return publish(cb,raw_msg);
			case 2: return fetch(cb,raw_msg);
			default:
				warnx << "incognito_impl::on_new_raw_message() - Error: Unknown request type " << raw_msg->request_type << ";\n";
				// FIXME - obsłużyć rządanie

		}
	}
}
void incognito_impl::on_new_raw_message_find_successor_cb(cb_onrm cb, ptr<incognito_raw_request> raw_msg, vec<chord_node> s, route search_path, chordstat status)
{
	if (status != CHORD_OK) {
		warnx << "incognito_impl::on_new_raw_message_find_successor_cb: find_successor failed: "
			<< status << " FIXME: " << __FILE__ << ":" << __LINE__ << "\n";
	} else {
		if (s.size()) {
			_encmngr->encrypt(s[0],raw_msg, wrap(mkref (this), &incognito_impl::on_new_raw_message_encrypt_cb, cb, s[0]));
		} else {
			warnx << "incognito_impl::on_new_raw_message_find_successor_cb: s.size()==0: "
				<< status << " FIXME: " << __FILE__ << ":" << __LINE__ << "\n";
		}
	}
}
void incognito_impl::on_new_raw_message_encrypt_cb(cb_onrm cb, chord_node n, ptr<incognito_encrypted_request> enc_msg, encmngr::encrypt_res res)
{
	if (res != encmngr::INCOGNITO_EM_ENCRYPT_OK) {
		warnx << "incognito_impl::on_new_raw_message_encrypt_cb(" << __FILE__ << ":"
			<< __LINE__ << "): FIXME FIXME FIXME - encryption of error message failed. Don't know what to do...";
		// return;	// FIXME
	}
	return doRPC (n, incognito_program_1, INCOGNITOPROC_ENC_MESSAGE,
		enc_msg, NULL, wrap (mkref(this),&incognito_impl::store_encrypted_data_cb));	// FIXME: wprowadzić poprawny callback

	//return a->reply(enc_msg);								// FIXME: to bzdura
}
// {{{  void incognito_impl::publish(user_args *a, ptr<incognito_raw_request> raw_msg)
void incognito_impl::publish(cb_onrm cb, ptr<incognito_raw_request> raw_msg)
{
	warnx << "incognito_impl::publish(a," << raw_msg->key_value << ");\n";
	warnx << "Publishing....\n";
	warnx << " key_type: >>" << raw_msg->key_type << "<< key_value: >>" << raw_msg->key_value <<"<<\n";

	// DEBUG - start
	char tab[]={
		'0','1','2','3',
		'4','5','6','7',
		'8','9','A','B',
		'C','D','E','F'};
	const char *p=raw_msg->data.base();
	warnx << "incognito_impl::publish() - raw_msg->data[" << raw_msg->data.size() << "]: ";
	for (unsigned int i=0;i<std::min(raw_msg->data.size(),(size_t)64);++i) {
		char c[3]={tab[((unsigned char)p[i])>>4],tab[((unsigned char)p[i])&0x0f],0};
		warnx << c;
	}
	warnx << "\n";
	// DEBUG - stop

/*----------------In case of NOAUTH block---------------------------------------------*/
	str data = str (raw_msg->data.base (), raw_msg->data.size ());
	str marshalled_data;
	if (raw_msg->key_type == DHASH_NOAUTH)
		marshalled_data = dhblock_noauth::marshal_block (data);
	else if (raw_msg->key_type == DHASH_CONTENTHASH)
		marshalled_data = dhblock_chash::marshal_block (data);
	else {
		warnx << "incognito_impl::publish: unknown key_type: "
			<< " FIXME: " << __FILE__ << ":" << __LINE__ << "\n";
		return;
	}
	
	ref<dhash_block> block = New refcounted<dhash_block> (marshalled_data, raw_msg->key_type);
/*------------------------------------------------------------------------------------*/

	block->ID = raw_msg->key_value;

	_dhcli->insert (block,
			wrap (mkref (this), &incognito_impl::publish_insert_cb2, cb));
}
// }}}  
// {{{ void incognito_impl::publish_insert_cb2 (user_args *a, dhash_stat status, vec<chordID> path)
void incognito_impl::publish_insert_cb2 (cb_onrm cb, dhash_stat status, vec<chordID> path)
{
	
	if (status != DHASH_OK) {
		warnx << "incognito_impl::publish_insert_cb: insert failed: "
			<< status << " FIXME: " << __FILE__ << ":" << __LINE__ << "\n";
	} else {
		warnx << "incognito_impl::publish_insert_cb: OK\n";
	}
	ptr<incognito_raw_request> raw_msg=New refcounted<incognito_raw_request>;
	raw_msg->request_type=1; // Store response
	raw_msg->status=status;
	return cb(raw_msg);
}
// }}} 
// {{{ Fetch
void incognito_impl::fetch(cb_onrm cb, ptr<incognito_raw_request> raw_msg)
{
	warnx <<  "incognito_impl::fetch() - raw_msg->key_type=" << raw_msg->key_type << "\n";
	warnx <<  "incognito_impl::fetch() - raw_msg->key_value=" << raw_msg->key_value << "\n";

	_dhcli->retrieve (blockID(raw_msg->key_value,raw_msg->key_type),
			wrap (mkref (this), &incognito_impl::fetch_retrieve_cb,cb));
}
void incognito_impl::fetch_retrieve_cb(cb_onrm cb, dhash_stat status, ptr<dhash_block> block, route path)
{
	warnx << "incognito_impl::fetch_retrieve_cb() status=" << status << "\n";

	ptr<incognito_raw_request> raw_msg=New refcounted<incognito_raw_request>;
	raw_msg->request_type=3; // Store response
	raw_msg->status=status;

	if (status != DHASH_OK) {
		warnx << "incognito_impl::fetch_retrieve_cb: stat != DHASH_OK"
			<< " FIXME: " << __FILE__ << ":" << __LINE__ << "\n";
		return cb(raw_msg);
	}
	vec<str> contents = get_block_contents (block->data, block->ctype);

	str buf;
	if (contents.size () == 1)
		buf = contents[0];
	else {
		assert (contents.size () > 0); 
		buf = contents[contents.size()-1];
	}   

	raw_msg->data.setsize(buf.len());
	memcpy (raw_msg->data.base (), buf.cstr(), buf.len());
	
	return cb(raw_msg);
}
// }}} 
// }}}
// {{{ Diffie-Hellman implementation
// {{{ void incognito_impl::on_dhkey_exchange(user_args *a)
void incognito_impl::on_dhkey_exchange(user_args *a)
{
	warnx << "incognito_impl::on_dhkey_exchange()\n";
	
	ptr<incognito_dh_res> res=New refcounted<incognito_dh_res>;
	incognito_dh_arg* arg = a->Xtmpl getarg<incognito_dh_arg> ();

	warnx << "incognito_impl::on_dhkey_exchange() - arg->caller_ID=" << arg->caller_ID << "\n";
	res->callee_pubkey=_keymngr->on_key_exchange(arg->caller_ID,arg->p,arg->g,arg->caller_pubkey);

	warnx << "incognito_impl::on_dhkey_exchange() - res->callee_pubkey=" << res->callee_pubkey << "\n";
	a->reply(res);

}
// }}}
// {{{ void incognito_impl::dh_exchange(chord_node &n, bigint p, bigint g, bigint pubkey, cb_dh_exchange cb)
void incognito_impl::dh_exchange(chord_node &n, bigint p, bigint g, bigint pubkey, cb_dh_exchange cb)
{
	warnx << "incognito_impl::dh_exchange()\n";

	incognito_dh_res *res=New incognito_dh_res;
	ptr<incognito_dh_arg> arg = New refcounted<incognito_dh_arg> ();
	arg->caller_ID = _host_node->my_ID();
	arg->p=p;
	arg->g=g;
	arg->caller_pubkey=pubkey;
	doRPC (n, incognito_program_1,
		INCOGNITOPROC_DHKEY_EXCHANGE, arg, res, wrap (mkref(this),&incognito_impl::dh_exchange_cb,cb,res));
}
// }}}
// {{{ void incognito_impl::dh_exchange_cb(cb_dh_exchange cb,incognito_dh_res *res,clnt_stat err)
void incognito_impl::dh_exchange_cb(cb_dh_exchange cb,incognito_dh_res *res,clnt_stat err)
{
	warnx << "incognito_impl::dh_exchange_cb() - clnt_stat=" << err << "\n";
	if (err)
	{
		warnx << "incognito_impl::dh_exchange_cb() - error="
			<< err << " FIXME: " << __FILE__ << ":" << __LINE__ << "\n";
		return;						// FIXME 
	}
	cb(res->callee_pubkey);
}
// }}}
// }}}  Diffie-Hellman implementation


// {{{ incognito_impl::doRPC 
void
incognito_impl::doRPC (const chord_node &n, const rpc_program &prog, int procno,
	           ptr<void> in,void *out, aclnt_cb cb,
		   cbtmo_t cb_tmo) 
{
  _host_node->doRPC (n, prog, procno, in, out, cb, cb_tmo);
}

void
incognito_impl::doRPC (const chord_node_wire &n, const rpc_program &prog,
                   int procno, ptr<void> in,void *out, aclnt_cb cb,
		   cbtmo_t cb_tmo) 
{
  _host_node->doRPC (make_chord_node (n), prog, procno, in, out, cb, cb_tmo);
}

void
incognito_impl::doRPC (ptr<location> ID, const rpc_program &prog, int procno,
	           ptr<void> in,void *out, aclnt_cb cb,
		   cbtmo_t cb_tmo)  
{
  _host_node->doRPC (ID, prog, procno, in, out, cb, cb_tmo);
}
// }}} i ncognito_impl::doRPC 

// vim: foldmethod=marker
